#include <fstream>
#include "AnimDescriptor.h"

using namespace game_engine::data_format;
using namespace game_engine::utils;

///////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
///////////////////////////////////////////////////////////////////////////////

AnimDescriptor::AnimDescriptor(void)
    : filename(), fileContent(), frameSize(), anchor()
{
    sequences.clear();
}

AnimDescriptor::AnimDescriptor(const string &file)
    : filename(file), fileContent(), frameSize(), anchor()
{
    sequences.clear();
}

AnimDescriptor::~AnimDescriptor(void)
{
}

///////////////////////////////////////////////////////////////////////////////
// Other public methods
///////////////////////////////////////////////////////////////////////////////

void AnimDescriptor::parse(const string &texture)
{
    // Read all content from input file and store it into a single string
    readAll();

    // Parse the contents
    doc.parse<0>(const_cast<char *>(fileContent.c_str()));

    // Create a new entry in sequences map for each sprite
    xml_node<> *node = doc.first_node("animation");

    // Loop through all <animation> nodes
    while (node != NULL)
    {
        // Get sprite filename
        xml_node<> *nodeName = node->first_node("filename");
        if (nodeName != NULL)
        {
            string file = nodeName->value();
            if (file == texture)
            {
                try
                {
                    getFrameSize(node);
                    getAnchorPoint(node);
                    vector<SequenceInfo> list = buildSequenceList(node);
                    sequences[file] = list;
                } catch (exception)
                {
                }
            }
        }

        // Look for next sprite
        node = node->next_sibling("animation");
    }
}

///////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////

const map<string, vector<SequenceInfo>>& AnimDescriptor::getAllSequences(void) 
    const
{
    return sequences;
}

const vector<SequenceInfo>& AnimDescriptor::getSequences(const string &name) 
    const
{
    map<string, vector<SequenceInfo>>::const_iterator it;
    it = sequences.find(name);
    if (it == sequences.end())
    {
        // TODO : throw exception
    }

    return (*it).second;
}

const Size& AnimDescriptor::getFrameSize(void) const
{
    return frameSize;
}

const Point& AnimDescriptor::getAnchor(void) const
{
    return anchor;
}

///////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////

void AnimDescriptor::readAll(void)
{
    // Read all contents from the file
    ifstream fin(filename.c_str(), ifstream::in);
    if (!fin || !fin.good() || fin.eof())
    {
        // throw exception
        string err("error reading in input file");
        throw runtime_error(err);
    }

    string content;
    while (!fin.eof())
    {
        getline(fin, content);
        fileContent += content + '\n';
    }
}

void AnimDescriptor::getFrameSize(xml_node<> *node)
{
    xml_node<> *nodeSize = node->first_node("frame_size");
    if (nodeSize != NULL)
    {
        xml_node<> *nodeWidth = nodeSize->first_node("width");
        frameSize.setWidth(atoi(nodeWidth->value()));
        xml_node<> *nodeHeight = nodeSize->first_node("height");
        frameSize.setHeight(atoi(nodeHeight->value()));
    }
    else
    {
        // TODO : throw exception
    }
}

void AnimDescriptor::getAnchorPoint(xml_node<> *node) 
{
    xml_node<> *nodeAnchor = node->first_node("anchor_point");
    if (nodeAnchor != NULL)
    {
        xml_node<> *nodeX = nodeAnchor->first_node("x");
        anchor.setX(atoi(nodeX->value()));
        xml_node<> *nodeY = nodeAnchor->first_node("y");
        anchor.setY(atoi(nodeY->value()));
    }
}

vector<SequenceInfo> AnimDescriptor::buildSequenceList(xml_node<> *node)
{
    vector<SequenceInfo> sequences;

    // Get first sequence node
    xml_node<> *seqNode = node->first_node("sequence");

    // Loop through all <sequence> nodes
    while (seqNode != NULL)
    {
        // Build new sequence
        SequenceInfo sequence;
        try
        {
            sequence.parse(seqNode);
        } catch (exception) 
        {
        }

        // Add sequence to vector
        sequences.push_back(sequence);

        // Look for next sequence
        seqNode = seqNode->next_sibling("sequence");
    } // while (seqNode != NULL)

    return sequences;
}
